package com.zmn.plat.common.util.encrypt;

import com.google.common.collect.Maps;
import com.zmn.common.utils.collection.CollectionUtil;
import com.zmn.plat.common.util.encrypt.annotation.EncryptDecryptField;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.reflect.FieldUtils;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 描述: 数据加密工具类
 *
 * @version v1.0
 * @author jiafei
 * @since 2021/8/26 18:31
 */
public class EncryptDecryptUtils {


	/**
	 * 描述: 获取需要加密或解密的字段
	 *
	 * @param parameterObject
	 * @return java.util.Map<java.lang.String, java.lang.String>
	 * @author jiafei
	 * @since 2021/8/25 17:51
	 */
	public static <T> Map<String, String> encryptFields(T parameterObject) throws IllegalAccessException {

		return pendingFields(parameterObject);
	}


	/**
	 * 描述: 获取需要加密或解密的字段
	 *
	 * @param result
	 * @return T
	 * @author jiafei
	 * @since 2021/8/25 18:02
	 */
	public static <T> Map<String, String> encryptdecrypt(T result) throws IllegalAccessException {

		return pendingFields(result);

	}


	/**
	 * 描述: 获取需要加密或解密的数据
	 *
	 * @param target
	 * @return java.util.Map<java.lang.String, java.lang.String>
	 * @author jiafei
	 * @since 2021/8/25 18:13
	 */
	public static <T> Map<String, String> pendingFields(T target) throws IllegalAccessException {

		Map<String, String> fieldMap = Maps.newHashMap();
		Field[] fields = FieldUtils.getAllFields(target.getClass());
		for (Field field : fields) {
			EncryptDecryptField annotation = field.getAnnotation(EncryptDecryptField.class);
			if (Objects.isNull(annotation)) {
				continue;
			}
			field.setAccessible(true);
			Object val = field.get(target);

			if (Objects.isNull(val)) {
				val = "";
			}

			fieldMap.put(field.getName(), Objects.toString(val));

		}
		return fieldMap;
	}

	/**
	 * 描述: 回填加密或解密后的数据
	 *
	 * @param target
	 * @param encryptData
	 * @author jiafei
	 * @since 2021/8/26 15:45
	 */
	public static <T> T backFillData(T target, Map<String, String> encryptData) throws IllegalAccessException {

		Field[] fields = FieldUtils.getAllFields(target.getClass());
		for (Field field : fields) {
			EncryptDecryptField annotation = field.getAnnotation(EncryptDecryptField.class);
			if (Objects.isNull(annotation)) {
				continue;
			}
			String val = encryptData.get(field.getName());
			field.setAccessible(true);
			field.set(target, val);
		}
		return target;
	}

	/**
	 * 描述: 获取指定注解
	 *
	 * @param target
	 * @param annotationClazz
	 * @return java.lang.annotation.Annotation
	 * @author jiafei
	 * @since 2021/9/9 9:40
	 */
	public static <T> Annotation getAnnotation(T target, Class<? extends Annotation> annotationClazz) {

		Annotation annotation = target.getClass().getAnnotation(annotationClazz);
		if (Objects.nonNull(annotation)) {
			return annotation;
		}
		Field[] fields = FieldUtils.getAllFields(target.getClass());
		for (Field field : fields) {
			Annotation annot = field.getAnnotation(annotationClazz);
			if (Objects.nonNull(annot)) {
				return annot;
			}
		}
		return null;
	}

	/**
	 * 描述: 获取需要加密的字段
	 *
	 * @param clazz
	 * @return java.util.List<java.lang.reflect.Field>
	 * @author jiafei
	 * @since 2021/9/9 13:41
	 */
	public static List<Field> getEncryptDecryptFields(Class<?> clazz) {

		Field[] fields = FieldUtils.getAllFields(clazz);
		return Arrays.stream(fields)
					 .filter(field -> Objects.nonNull(field.getAnnotation(EncryptDecryptField.class)))
					 .collect(Collectors.toList());

	}


	/**
	 * 描述: 批量加密解密的数据
	 *
	 * @param params
	 * @return java.util.Map<java.lang.String, java.util.List < java.lang.String>>
	 * @author jiafei
	 * @since 2021/9/23 19:11
	 */
	public static <T> Map<String, Map<String, String>> batchEncryptDecrypt(List<T> params, String key) throws IllegalAccessException {

		Map<String, Map<String, String>> batchEncryptFieldMap = new HashMap<>(params.size());
		for (T param : params) {
			Map<String, String> map = pendingFields(param);
			for (Map.Entry<String, String> entry : map.entrySet()) {
				if (StringUtils.isEmpty(entry.getValue())) {
					continue;
				}
				Map<String, String> listMap = batchEncryptFieldMap.get(entry.getKey());
				if (CollectionUtil.isNullOrEmpty(listMap)) {
					listMap = new HashMap<>(params.size());
					batchEncryptFieldMap.put(entry.getKey(), listMap);
				}
				String index = getIndex(param, key);
				listMap.put(index, entry.getValue());
			}
		}
		return batchEncryptFieldMap;
	}


	public static <T> void batchBackFillData(List<T> data, Map<String, Map<String, String>> encryptDecryptMap, String key) throws IllegalAccessException {

		Class<?> clazz = data.get(0).getClass();
		List<Field> encryptDecryptFields = getEncryptDecryptFields(clazz);
		for (T t : data) {
			for (Field decryptField : encryptDecryptFields) {
				Map<String, String> map = encryptDecryptMap.get(decryptField.getName());
				if (CollectionUtil.isNullOrEmpty(map)) {
					continue;
				}
				String index = getIndex(t, key);
				String s = map.get(index);
				if (Objects.isNull(s)){
					continue;
				}
				decryptField.setAccessible(true);
				decryptField.set(t, s);
			}
		}

	}

	/**
	 * 获取每个对象的唯一标识
	 */
	private static String getIndex(Object obj, String key) throws IllegalAccessException {

		String index = null;
		Field[] fields = FieldUtils.getAllFields(obj.getClass());
		for (Field field : fields) {
			if (StringUtils.equals(key, field.getName())) {
				field.setAccessible(true);
				Object fieldValue = field.get(obj);
				if (Objects.nonNull(fieldValue)) {
					index = String.valueOf(fieldValue);
				}
			}
		}
		if (index == null) {
			// 根据对象生成唯一标识
			return Integer.toHexString(System.identityHashCode(obj));
		}
		return index;
	}

}
